﻿using EasyElasticLogger.NETFramework.ES.Configuration;
using Elasticsearch.Net;
using Nest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EasyElasticLogger.NETFramework.ES.Clients
{
    /// <summary>
    /// Elasticsearch 客户端工厂。
    /// 基于配置创建带 Basic 认证的 NEST 客户端，并确保线程安全的单例访问。
    /// </summary>
    internal static class ElasticClientFactory
    {
        /// <summary>
        /// 懒加载的 ElasticClient 实例。
        /// 使用 Lazy{T} 确保线程安全且仅初始化一次。
        /// </summary>
        private static Lazy<ElasticClient> _lazyClient;
        
        /// <summary>
        /// 当前使用的配置
        /// </summary>
        private static LoggerConfiguration _currentConfig;

        /// <summary>
        /// 获取已配置的 ElasticClient 实例。
        /// 如果配置中未启用集群连接，则返回 null。
        /// </summary>
        public static ElasticClient Instance
        {
            get
            {
                // 使用新配置方式
                return _currentConfig?.Cluster != null && _currentConfig.Cluster.Nodes.Any() ? _lazyClient?.Value : null;
            }
        }

        /// <summary>
        /// 使用指定配置初始化客户端
        /// </summary>
        /// <param name="config">日志记录器配置</param>
        public static void Initialize(LoggerConfiguration config)
        {
            _currentConfig = config ?? throw new ArgumentNullException(nameof(config));
            
            // 重新初始化客户端
            // 由于Lazy<T>创建的值无法重置，我们需要重新创建Lazy实例
            _lazyClient = new Lazy<ElasticClient>(CreateClient);
        }

        /// <summary>
        /// 创建并配置 ElasticClient 实例。
        /// 包括：集群节点、Basic 认证、超时设置等。
        /// </summary>
        /// <returns>配置好的 ElasticClient</returns>
        private static ElasticClient CreateClient()
        {
            // 使用新配置方式
            if (_currentConfig != null)
            {
                return CreateClientFromNewConfig(_currentConfig);
            }
            
            throw new InvalidOperationException("未提供有效的日志记录器配置。");
        }
        
        /// <summary>
        /// 根据新配置创建ElasticClient
        /// </summary>
        /// <param name="config">日志记录器配置</param>
        /// <returns>ElasticClient实例</returns>
        private static ElasticClient CreateClientFromNewConfig(LoggerConfiguration config)
        {
            if (config.Cluster == null || !config.Cluster.Nodes.Any())
                throw new ArgumentException("Elasticsearch 节点地址不能为空。");

            // 解析节点地址
            var nodeUris = config.Cluster.Nodes
                .Select(s => new Uri(s.Trim()))
                .ToList();

            if (nodeUris.Count == 0)
                throw new ArgumentException("Elasticsearch 节点地址不能为空。");

            // 根据节点数量选择连接池类型
            IConnectionPool connectionPool;
            if (nodeUris.Count == 1)
            {
                // 单节点模式
                connectionPool = new SingleNodeConnectionPool(nodeUris.First());
            }
            else
            {
                // 集群模式
                connectionPool = new StaticConnectionPool(nodeUris);
            }

            // 配置客户端
            var settings = new ConnectionSettings(connectionPool)
                .EnableApiVersioningHeader(false)
                .DisableDirectStreaming()
                .RequestTimeout(TimeSpan.FromMilliseconds(config.Cluster.ConnectionTimeoutMs));

            // 配置认证信息
            if (!string.IsNullOrEmpty(config.Cluster.Username) && !string.IsNullOrEmpty(config.Cluster.Password))
            {
                settings.BasicAuthentication(config.Cluster.Username, config.Cluster.Password);
            }

            // 配置SSL
            if (config.Cluster.UseSsl)
            {
                settings.EnableHttpCompression();
                
                if (config.Cluster.SkipSslVerification)
                {
                    settings.ServerCertificateValidationCallback((sender, cert, chain, errors) => true);
                }
            }

            // 配置重试策略
            if (config.Cluster.MaxRetries > 0)
            {
                settings.MaximumRetries(config.Cluster.MaxRetries);
            }

            return new ElasticClient(settings);
        }
    }
}